package org.cainiao.api.lark.impl.reactive.authenticateandauthorize.getaccesstokens;

import lombok.RequiredArgsConstructor;
import org.cainiao.api.lark.dto.response.LarkDataResponse;
import org.cainiao.api.lark.dto.response.authenticateandauthorize.getaccesstokens.AppAccessTokenResponse;
import org.cainiao.api.lark.dto.response.authenticateandauthorize.getaccesstokens.LarkTokenInfo;
import org.cainiao.api.lark.impl.util.converter.ResponseConverter;
import org.cainiao.api.lark.reactive.authenticateandauthorize.getaccesstokens.restoperations.GetAccessTokens;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.Map;

import static org.cainiao.api.lark.util.Util.AUTHEN_MODULE_URI;
import static org.cainiao.api.lark.util.Util.AUTH_MODULE_URI;

/**
 * 靠 RestOperations 切换 HTTP 客户端<br />
 * <p>
 * Author: Cai Niao(wdhlzd@163.com)<br />
 */
@RequiredArgsConstructor
public class WebClientGetAccessTokens implements GetAccessTokens {

    private final WebClient webClient;
    private final String baseUrl;
    private final ResponseConverter responseConverter;

    @Override
    public Mono<AppAccessTokenResponse> getCustomAppAppAccessToken(String appId, String appSecret) {
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("app_id", appId);
        formData.add("app_secret", appSecret);

        return webClient.post()
            .uri(String.format("%s%s/app_access_token/internal", baseUrl, AUTH_MODULE_URI))
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromFormData(formData))
            .retrieve()
            .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
            })
            .map(responseConverter::convertToAppAccessTokenResponse);
    }

    @Override
    public Mono<LarkDataResponse<LarkTokenInfo>> refreshUserAccessToken(String grantType, String refreshToken) {
        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
        formData.add("grant_type", grantType);
        formData.add("refresh_token", refreshToken);

        return webClient.post()
            .uri(String.format("%s%s/oidc/refresh_access_token", baseUrl, AUTHEN_MODULE_URI))
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON)
            .body(BodyInserters.fromFormData(formData))
            .retrieve()
            .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
            })
            .map(responseConverter::convertToLarkTokenInfoResponse);
    }
}
